/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */

package org.huihoo.orbas.orb.cdr;

/**
 * <p>Description: </p>
 * CDR decode stream.
 * <p>Copyright (c) 2002,2003</p>
 * <p>Company: <a href="http://www.huihoo.org/">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~mep">mep(mep@huihoo.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

import com.cognition.util.StringTokenizer;
import com.cognition.util.j2me.DataTypeUtil;
import com.cognition.util.j2me.J2MESerializable;
import org.omg.CORBA.TCKind;

public class CDRInputStream extends org.omg.CORBA_2_3.portable.InputStream {
    protected byte[] buffer;
    protected int bufferLength;
    protected int nextByteToRead;
    public boolean littleEndian;
    public org.omg.CORBA.ORB orb;
    int mark;

    private java.util.Hashtable valueList;
    private int indirection;
    private java.util.Vector graph;

    public CDRInputStream(org.omg.CORBA.ORB orb, byte[] buf) {
        this.orb = orb;
        this.buffer = buf;
        this.nextByteToRead = 0;
        this.bufferLength = buf.length;
        this.mark = 0;
        this.littleEndian = false;

        this.valueList = new java.util.Hashtable();
        this.graph = new java.util.Vector();
    }

    public CDRInputStream(byte[] buf) {
        this(null, buf);
    }

    public boolean markSupported() {
        return true;
    }

    public void mark() {
        mark = nextByteToRead;
    }

    public void reset() {
        nextByteToRead = mark;
    }

    public CDRInputStream read_encapsulation() {
        //        mark();
        int length = this.read_long();
        //        reset();
        byte[] value = new byte[length];
        System.arraycopy(buffer, 0, value, 0, length);

        return new CDRInputStream(this.orb, value);
    }

    public final byte read_octet() {
        return buffer[nextByteToRead++];
    }

    public final void read_octet_array(byte[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_octet();
        }
    }

    public final boolean read_boolean() {
        return read_octet() != 0;
    }

    public final void read_boolean_array(
        boolean[] value,
        int offset,
        int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_boolean();
        }
    }

    public final char read_char() {
        //here for eliminate of the hi byte of char
        return (char) (((char)read_octet()) & 0xFF);
    }

    public final void read_char_array(char[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_char();
        }
    }

    public String read_string() {
        int length = read_long();

        if (length <= 0) {
            throw new org.omg.CORBA.MARSHAL("Invalid string length");
        }

        byte[] ret = new byte[length - 1];

        for (int i = 0; i < length - 1; i++) {
            ret[i] = read_octet();
        }
        read_octet();
        return new String(ret);
    }

    public final double read_double() {
        return Double.longBitsToDouble(read_longlong());
    }

    public final void read_double_array(
        double[] value,
        int offset,
        int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_double();
        }
    }

    public final float read_float() {
        return Float.intBitsToFloat(read_long());
    }

    public final void read_float_array(float[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_float();
        }
    }

    public final int read_long() {
        alignment(4);
        int first = read_octet();
        int second = read_octet();
        int third = read_octet();
        int fourth = read_octet();

        if (littleEndian) {
            return (fourth & 0xFF)
                << 24 | (third & 0xFF)
                << 16 | (second & 0xFF)
                << 8 | (first & 0xFF);
        }
        else {
            return (first & 0xFF)
                << 24 | (second & 0xFF)
                << 16 | (third & 0xFF)
                << 8 | (fourth & 0xFF);
        }
    }

    public final void read_long_array(int[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_long();
        }
    }

    public final long read_longlong() {
        alignment(8);

        long first = (long)read_long();
        long second = (long)read_long();

        if (littleEndian) {
            return (second << 32) | (first & 0xFFFFFFFFL);
        }
        else {
            return (first << 32) | (second & 0xFFFFFFFFL);
        }
    }

    public final void read_longlong_array(
        long[] value,
        int offset,
        int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_longlong();
        }
    }

    public final short read_short() {
        alignment(2);
        byte first = read_octet();
        byte second = read_octet();

        if (littleEndian) {
            return (short) (((second & 0xff) << 8) | ((first & 0xff) << 0));
        }
        else {
            return (short) (((first & 0xff) << 8) | ((second & 0xff) << 0));
        }
    }

    public final void read_short_array(short[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_short();
        }
    }

    public final char read_wchar() {
        //GIOP1.2?
        return (char)read_short();
    }

    public final void read_wchar_array(char[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_wchar();
        }
    }

    public final String read_wstring() {
        int length = read_long();

        char[] ret = new char[length - 1];

        for (int i = 0; i < length - 1; i++) {
            ret[i] = read_wchar();
        }
        read_wchar();
        return new String(ret);
    }

    public final short read_ushort() {
        return read_short();
    }

    public final void read_ushort_array(
        short[] value,
        int offset,
        int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_ushort();
        }
    }

    public final int read_ulong() {
        return read_long();
    }

    public final void read_ulong_array(int[] value, int offset, int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_ulong();
        }
    }

    public final long read_ulonglong() {
        return read_longlong();
    }

    public final void read_ulonglong_array(
        long[] value,
        int offset,
        int length) {
        for (int i = 0; i < length; i++) {
            value[i + offset] = read_ulonglong();
        }
    }

    public final org.omg.CORBA.Any read_any() {
        org.omg.CORBA.Any any = orb.create_any();
        org.omg.CORBA.TypeCode typecode = read_TypeCode();

        any.read_value(this, typecode);

        return any;
    }

    public final org.omg.CORBA.Object read_Object() {

        org.huihoo.orbas.orb.ior.IorParser p =
            new org.huihoo.orbas.orb.ior.IorParser(orb, this);

        return p.getObject();

    }

    public org.omg.CORBA.Object read_Object(java.lang.Class clz) {

        org.huihoo.orbas.orb.ior.IorParser p =
            new org.huihoo.orbas.orb.ior.IorParser(orb, this);

        org.omg.CORBA.Object value = p.getObject();
        org.omg.CORBA.portable.ObjectImpl objectImpl =
            (org.omg.CORBA.portable.ObjectImpl)value;

        if (objectImpl == null) {
            //report an error
            System.out.println("CDROutputStream: Not a CORBA Object.");
        }

        org.huihoo.orbas.orb.types.ObjRefDelegate delegate =
            (org.huihoo.orbas.orb.types.ObjRefDelegate) (objectImpl._get_delegate());

        Object stub = null;
        try {
            stub = clz.newInstance();
        }
        catch (InstantiationException e1) {
            System.out.println(
                "CDRInputStream read_Object: Instantiation Exception");
        }
        catch (IllegalAccessException e2) {
            System.out.println(
                "CDRInputStream read_Object: IllegalAccess Exception");
        }

        org.omg.CORBA.portable.ObjectImpl ret =
            (org.omg.CORBA.portable.ObjectImpl)stub;

        ret._set_delegate(delegate);

        return ret;
    }

    public org.omg.CORBA.TypeCode read_TypeCode() {
        int kind = read_long();

        switch (kind) {

            case TCKind._tk_null :
            case TCKind._tk_void :
            case TCKind._tk_short :
            case TCKind._tk_long :
            case TCKind._tk_ushort :
            case TCKind._tk_ulong :
            case TCKind._tk_float :
            case TCKind._tk_double :
            case TCKind._tk_boolean :
            case TCKind._tk_char :
            case TCKind._tk_octet :
            case TCKind._tk_any :
            case TCKind._tk_TypeCode :
            case TCKind._tk_longlong :
            case TCKind._tk_ulonglong :
            case TCKind._tk_longdouble :
            case TCKind._tk_wchar :

                return orb.get_primitive_tc(
                    org.omg.CORBA.TCKind.from_int(kind));
                //            break;

            case TCKind._tk_Principal :
                throw new org.omg.CORBA.NO_IMPLEMENT("Principal deprecated");
                //            break;
            case TCKind._tk_objref :
                String objrefID = read_string();
                String objrefName = read_string();

                return orb.create_interface_tc(objrefID, objrefName);

            case TCKind._tk_enum :
                String enumId = read_string();
                String enumName = read_string();
                int enumMemCount = read_long();
                String enumMembers[] = new String[enumMemCount];

                for (int i = 0; i < enumMemCount; i++) {
                    enumMembers[i] = read_string();
                }

                return orb.create_enum_tc(enumId, enumName, enumMembers);
                //            break;

            case TCKind._tk_struct :
                String structId = read_string();
                String structName = read_string();
                int structMemCount = read_long();
                org.omg.CORBA.StructMember[] structMembers =
                    new org.omg.CORBA.StructMember[structMemCount];

                for (int i = 0; i < structMemCount; i++) {
                    String memberName = read_string();
                    org.omg.CORBA.TypeCode type = read_TypeCode();

                    structMembers[i] =
                        new org.omg.CORBA.StructMember(memberName, type, null);
                }

                return orb.create_struct_tc(
                    structId,
                    structName,
                    structMembers);
                //            break;
            case TCKind._tk_except :
                String exceptId = read_string();
                String exceptName = read_string();
                int exceptMemCount = read_long();
                org.omg.CORBA.StructMember[] exceptMembers =
                    new org.omg.CORBA.StructMember[exceptMemCount];

                for (int i = 0; i < exceptMemCount; i++) {
                    String memberName = read_string();
                    org.omg.CORBA.TypeCode type = read_TypeCode();

                    exceptMembers[i] =
                        new org.omg.CORBA.StructMember(memberName, type, null);
                }

                return orb.create_exception_tc(
                    exceptId,
                    exceptName,
                    exceptMembers);
                //            break;

            case TCKind._tk_union :
                String unionId = read_string();
                String unionName = read_string();
                org.omg.CORBA.TypeCode unionTypeCode = read_TypeCode();
                int defaultIndex = read_long();
                int unionMemCount = read_long();
                org.omg.CORBA.UnionMember[] unionMembers =
                    new org.omg.CORBA.UnionMember[unionMemCount];

                for (int i = 0; i < unionMemCount; i++) {
                    //Unknow what to do
                    //                throw new org.omg.CORBA.NO_IMPLEMENT();
                    org.omg.CORBA.Any theLabel = read_any();
                    String memberName = read_string();
                    org.omg.CORBA.TypeCode type = read_TypeCode();

                    unionMembers[i] =
                        new org.omg.CORBA.UnionMember(
                            memberName,
                            theLabel,
                            type,
                            null);
                }

                return orb.create_union_tc(
                    unionId,
                    unionName,
                    unionTypeCode,
                    unionMembers);
                //            break;

            case TCKind._tk_alias :
                String aliasId = read_string();
                String aliasName = read_string();

                org.omg.CORBA.TypeCode aliasType = read_TypeCode();

                return orb.create_alias_tc(aliasId, aliasName, aliasType);
                //            break;

            case TCKind._tk_abstract_interface :
                String abstractInfId = read_string();
                String abstractInfName = read_string();

                return orb.create_abstract_interface_tc(
                    abstractInfId,
                    abstractInfName);
                //            break;

            case TCKind._tk_sequence :
                int seqLength = read_long();
                org.omg.CORBA.TypeCode seqElemType = read_TypeCode();

                return orb.create_sequence_tc(seqLength, seqElemType);
                //            break;

            case TCKind._tk_string :
                int stringBound = read_long();

                return orb.create_string_tc(stringBound);
                //            break;
            case TCKind._tk_array :
                org.omg.CORBA.TypeCode arrayType = read_TypeCode();
                int arrayCount = read_long();

                orb.create_array_tc(arrayCount, arrayType);
                break;
            case TCKind._tk_wstring :
                int wstringBound = read_long();

                return orb.create_string_tc(wstringBound);
                //            break;
            case TCKind._tk_fixed :
                throw new org.omg.CORBA.NO_IMPLEMENT();
                //            break;
            case TCKind._tk_value :
                throw new org.omg.CORBA.NO_IMPLEMENT();
                //            break;
            case TCKind._tk_value_box :
                throw new org.omg.CORBA.NO_IMPLEMENT();
                //            break;
            case TCKind._tk_native :
                String nativeId = read_string();
                String nativeName = read_string();

                orb.create_native_tc(nativeId, nativeName);
                //            break;
                //        case TCKind._tk_local_interface:
                //            String localId = read_string();
                //            String localName = read_string();
                //            
                //            orb.create_local_interface_tc(localId, localName);
                //            break;
            default :
                System.out.println(
                    "CDRInputStream Invalid TCKind code: " + kind);
                return null;

        }

        System.out.println("Invalid TCKind code: " + kind);
        return null;
    }

    public org.omg.CORBA.Context read_Context() {
        //do nothing
        return null;
    }



    public J2MESerializable read_value() {
        String[] id = null;
        byte[] buf = null;
        String[] codeBase = null;
        J2MESerializable ser = null;
        int size = 0;
        java.lang.Class clz;
        java.lang.Object object;

        alignment(4);
        indirection = nextByteToRead;

        int tag = read_long();

        if (tag == 0xffffffff) {
            int index = read_long();
            index = index + nextByteToRead - 4;

            ser = getValueFromList(index);

            if (ser == null) {
                mark();
                nextByteToRead = index;
                ser = read_value();
                reset();

                if (ser == null) {
                    throw new org.omg.CORBA.MARSHAL("Invalid indirection");
                }
            }

            return ser;
        }

        if (tag == 0) {
            return null;
        }

        if (!((tag >= 0x7fffff00) && (tag <= 0x7fffffff))) {
            throw new org.omg.CORBA.MARSHAL("Invalid value tag");
        }

        if ((tag & 0x00000001) == 1) {
			codeBase = readValueCodeBase();
        }

        if ((tag & 0x00000006) == 2) {
			id = new String[1];

			id[0] = readValueRepId();
        }

        if ((tag & 0x00000006) == 6) {
            id = readValueRepIdList();
        }

        size = 0;

        if ((tag & 0x00000008) == 8) {
            size = read_long();
            buf = new byte[size];

            read_octet_array(buf, 0, size);
        }

        org.omg.CORBA.portable.ValueFactory factory = null;
        int i = 0;

        try {
            while (true) {
                if (factory == null && orb instanceof org.huihoo.orbas.orb.ORB) {
                    org.huihoo.orbas.orb.ORB huiOrb =
                            (org.huihoo.orbas.orb.ORB)orb;
                    factory = huiOrb.lookup_value_factory(id[i]);
                }

                if (factory == null) {
                    try {
                        factory = loadFactory(id[i], codeBase);
                    }
                    catch (org.omg.CORBA.MARSHAL ex) {
                    }

                    i++;

                    if (i == id.length) {
                        break;
                    }

                }
                else {
                    break;
                }
            }
        }
        catch (java.lang.Exception ex) {
            ex.printStackTrace();
            throw new org.omg.CORBA.MARSHAL();
        }

        if (factory == null) {
            throw new org.omg.CORBA.MARSHAL();
        }

        if (size == 0) {
            ser = factory.read_value(this);
        }
        else {
            CDRInputStream input = new CDRInputStream(getBuffer());
            input.setLittleEndian(getLittleEndian());
            ser = factory.read_value(input);
        }

        if ((tag & 0x00000008) == 8) {
            read_long();
        }
        
		putValueToList(indirection, ser);
        return ser;
    }

    public com.cognition.util.j2me.J2MESerializable read_value(java.lang.String rep_id) {
        String[] id = null;
        byte[] buf = null;
        String[] codeBase = null;
        com.cognition.util.j2me.J2MESerializable ser = null;
        int size = 0;
        java.lang.Class clz;
        java.lang.Object object;

        alignment(4);
        indirection = nextByteToRead;

        int tag = read_long();

        if (tag == 0xffffffff) {
            int index = read_long();
            index = index + nextByteToRead - 4;

            ser = getValueFromList(index);

            if (ser == null) {
                mark();
                nextByteToRead = index;
                ser = read_value();
                reset();

                if (ser == null) {
                    throw new org.omg.CORBA.MARSHAL("Invalid indirection");
                }
            }

            return ser;
        }

        if (tag == 0) {
            return null;
        }

        if (!((tag >= 0x7fffff00) && (tag <= 0x7fffffff))) {
            throw new org.omg.CORBA.MARSHAL("Invalid value tag");
        }

        if ((tag & 0x00000001) == 1) {
            codeBase = readValueCodeBase();
        }

        if ((tag & 0x00000006) == 2) {
            id = new String[1];

			id[0] = readValueRepId();
        }

        if ((tag & 0x00000006) == 6) {
            id = readValueRepIdList();
        }

        boolean found = false;

        for (int i = 0; i < id.length; i++) {
            if (id[i].equals(rep_id)) {
                found = true;
            }
        }

        if (!found) {
            throw new org.omg.CORBA.BAD_PARAM();
        }

        size = 0;
        if ((tag & 0x00000008) == 8) {
            size = read_long();
            buf = new byte[size];
            read_octet_array(buf, 0, size);
        }

        org.omg.CORBA.portable.ValueFactory factory = null;
        int i = 0;
        try {
            while (true) {
                if (factory == null && orb instanceof org.huihoo.orbas.orb.ORB) {
                    org.huihoo.orbas.orb.ORB huiOrb =
                            (org.huihoo.orbas.orb.ORB)orb;
                    factory = huiOrb.lookup_value_factory(id[i]);
                }

                if (factory == null) {
                    try {
                        factory = loadFactory(id[i], codeBase);
                    }
                    catch (org.omg.CORBA.MARSHAL ex) {
                    }

                    i++;

                    if (i == id.length) {
                        break;
                    }
                }
                else {
                    break;
                }
            }
        }
        catch (java.lang.Exception ex) {
            ex.printStackTrace();
            throw new org.omg.CORBA.MARSHAL();
        }

        if (factory == null) {
            throw new org.omg.CORBA.MARSHAL();
        }

        if (size == 0) {
            ser = factory.read_value(this);
        }
        else {
            CDRInputStream input = new CDRInputStream(getBuffer());
            input.setLittleEndian(getLittleEndian());
            ser = factory.read_value(input);
        }

        if ((tag & 0x00000008) == 8) {
            read_long();
        }
        
		putValueToList(indirection, ser);
        return ser;

    }

    public com.cognition.util.j2me.J2MESerializable read_value(java.lang.Class clz) {
        java.lang.Object value = null;

        try {
            value = clz.newInstance();
        }
        catch (InstantiationException ex) {
            throw new org.omg.CORBA.BAD_PARAM(
                "Unable to create an instance of " + clz.getName());
        }
        catch (IllegalAccessException ex) {
            throw new org.omg.CORBA.BAD_PARAM(
                "Unable to access to " + clz.getName());
        }

        if (value instanceof com.cognition.util.j2me.J2MESerializable) {
            return read_value((com.cognition.util.j2me.J2MESerializable)value);
        }

        throw new org.omg.CORBA.BAD_PARAM();
    }

    public com.cognition.util.j2me.J2MESerializable read_value(
        org.omg.CORBA.portable.BoxedValueHelper factory) {
        String[] id;
        String[] codeBase = null;

        alignment(4);
        indirection = nextByteToRead;

        int tag = read_long();

        if (tag == 0xffffffff) {
            int index = read_long();
            index = index + nextByteToRead - 4;

            com.cognition.util.j2me.J2MESerializable ser = getValueFromList(index);

            if (ser == null) {

                mark();
                nextByteToRead = index;
                ser = read_value();
                reset();

                if (ser == null) {
                    throw new org.omg.CORBA.MARSHAL("Invalid indirection");
                }
            }

            return ser;
        }

        if (tag == 0) {
            return null;
        }

        if (!((tag >= 0x7fffff00) && (tag <= 0x7fffffff))) {
            throw new org.omg.CORBA.MARSHAL("Invalid value tag");
        }

        if ((tag & 0x00000001) == 1) {
            codeBase = readValueCodeBase();
        }

        if ((tag & 0x00000006) == 2) {
            id = new String[1];
            
			id[0] = readValueRepId();

            if (!id[0].equals(factory.get_id())) {
                throw new org.omg.CORBA.MARSHAL();
            }
        }

        com.cognition.util.j2me.J2MESerializable ret = factory.read_value(this);
        putValueToList(indirection, ret);
        return ret;
    }

    public com.cognition.util.j2me.J2MESerializable read_value(com.cognition.util.j2me.J2MESerializable value) {

        if (value instanceof org.omg.CORBA.portable.CustomValue) {
            org.omg.CORBA.portable.CustomValue customValue;
            customValue = (org.omg.CORBA.portable.CustomValue)value;
            org.omg.CORBA.DataInputStream inputStream =
                new org.huihoo.orbas.orb.io.InputStream(this);
            customValue.unmarshal(inputStream);

            return value;
        }
        else {
            if (value instanceof org.omg.CORBA.portable.StreamableValue) {
            	//resolve circulation graph of valuetype
            	putValueToList(indirection, value);
                ((org.omg.CORBA.portable.StreamableValue) (value))._read(this);

                return value;
            }
        }

        throw new org.omg.CORBA.BAD_PARAM();

    }

    public java.lang.Object read_abstract_interface() {
        throw new org.omg.CORBA.NO_IMPLEMENT();
    }

    public java.lang.Object read_abstract_interface(java.lang.Class clz) {
        throw new org.omg.CORBA.NO_IMPLEMENT();
    }

    protected org.omg.CORBA.portable.ValueFactory loadFactory(
        String id,
        String[] codeBase) {
        org.omg.CORBA.portable.ValueFactory factory = null;

        if (id.startsWith("IDL")) {
            String baseName = id.substring(4, DataTypeUtil.lastIndexOf(id, ":"));

            baseName = baseName.replace('/', '.');
            String factoryName = baseName + "DefaultFactory";

            //			load factory class
            try {
                factory =
                    (org.omg.CORBA.portable.ValueFactory)(Class
                        .forName(factoryName)
                        .newInstance());
             }
            catch (ClassNotFoundException ec) {
                System.out.println(ec.toString());
            }
            catch (java.lang.InstantiationException ei) {
				System.out.println(ei.toString());
            }
            catch (java.lang.IllegalAccessException eill) {
				System.out.println(eill.toString());
            }
        }
        
        return factory;

    }

    protected J2MESerializable getValueFromList(int index) {
        java.util.Enumeration en = valueList.keys();

        java.lang.Integer val = null;

        while (en.hasMoreElements()) {
            val = (java.lang.Integer)en.nextElement();

            if (val.intValue() == index)
                return (com.cognition.util.j2me.J2MESerializable)valueList.get(val);
        }

        return null;
    }

    protected void putValueToList(int index, com.cognition.util.j2me.J2MESerializable value) {
        valueList.put(new Integer(index), value);
    }

    void alignment(int alignSize) {
        int boundary = (nextByteToRead) % alignSize;

        if (boundary != 0)
            nextByteToRead += alignSize - boundary; // skip padding
    }

	protected String[] readValueCodeBase() {
		String[] codeBase = null;
		
		mark();
		String url;
		int tag = read_long();
		
		if( tag == 0xffffffff ) {
			//read indirection string
			int index = read_long();
			
			// old mark is lost
			mark();
			
			nextByteToRead = nextByteToRead + index - 4;
			url = read_string();
			
			reset();
		}
		else {
			reset();
			url = read_string();
		}

        StringTokenizer tokens = new StringTokenizer(url);
		codeBase = new String[tokens.countTokens()];
		
		int i = 0;
		
		while(tokens.hasMoreTokens()) {
			codeBase[i] = tokens.nextToken();
			i++;
		}
					
		return codeBase;
	}
	
	protected String readValueRepId() {
		String id = null;
		
		mark();
		int tag = read_long();
		
		if( tag == 0xffffffff ) {
			//read indirection string
			int index = read_long();
			
			// old mark is lost
			mark();
			
			nextByteToRead = nextByteToRead + index - 4;
			id = read_string();
			
			reset();
		}
		else {
			reset();
			id = read_string();
		}
		
		return id;
	}
	
	protected String[] readValueRepIdList() {
		String[] id = null;
		
		int length = read_long();
		id = new String[ read_long() ];
		
		for(int i=0; i<length; i++) {
			id[i] = readValueRepId();
		}
		
		return id;
	}
	
    public void setLittleEndian(boolean endian) {
        littleEndian = endian;
    }

    public boolean getLittleEndian() {
        return littleEndian;
    }

    void skip(int n) {
        nextByteToRead += n;
    }

    public boolean isEnd() {
        return nextByteToRead >= bufferLength;
    }

    public byte[] getBuffer() {
        return buffer;
    }
}
